package main

import (
	"context"
	"fmt"
	"github.com/neo4j/neo4j-go-driver/v5/neo4j"
)

func main() {
	dbUri := "neo4j://localhost" // scheme://host(:port) (default port is 7687)
	driver, err := neo4j.NewDriverWithContext(dbUri, neo4j.BasicAuth("neo4j", "81851406", ""))
	if err != nil {
		panic(err)
	}
	ctx := context.Background()
	defer driver.Close(ctx)

	type opt int
	const (
		_getPath opt = iota + 1
		_createItem
		_getItem
		_addEdge
		_getEdge
	)
	var cmd = _getPath
	switch cmd {
	default:
		fmt.Println("指定cmd")
	case _createItem:
		item, err := createItem(ctx, driver)
		if err != nil {
			panic(err)
		}
		fmt.Printf("%v\n", item)
	case _getItem:
		item, err := getItem(ctx, driver)
		if err != nil {
			panic(err)
		}
		fmt.Println(*item)

	case _addEdge:
		err := addEdge(ctx, driver)
		if err != nil {
			panic(err)
		}

	case _getEdge:
		getEdge(ctx, driver)

	case _getPath:
		getPath(ctx, driver)

	}

}

// 获取路径
func getPath(ctx context.Context, driver neo4j.DriverWithContext) {
	res, err := neo4j.ExecuteQuery(ctx, driver, `match p=(:Person{name:$name})-[*..3]-() return p`, map[string]any{"name": "张三"}, neo4j.EagerResultTransformer)
	if err != nil {
		panic(err)
	}
	for _, r := range res.Records {
		v, b, err := neo4j.GetRecordValue[neo4j.Path](r, "p")
		if err != nil {
			panic(err)
		}
		if !b {
			for _, edge := range v.Relationships {
				fmt.Println(edge)
			}
		}
	}
}

// 修改边
func updateEdge() {

}

// 删除边
func deleteEdge() {

}

// 获取边
func getEdge(ctx context.Context, driver neo4j.DriverWithContext) {
	res, err := neo4j.ExecuteQuery(ctx, driver, `match (:Person{name:'张三2'})-[r]-() return r`, map[string]any{}, neo4j.EagerResultTransformer)
	if err != nil {
		panic(err)
	}
	for _, r := range res.Records {
		v, isNil, err := neo4j.GetRecordValue[neo4j.Relationship](r, "r")
		if err != nil {
			panic(err)
		}
		if !isNil {
			fmt.Println(v.StartElementId, v.EndElementId, v.Type, v.Props)
		}
	}
}

// 添加边
func addEdge(ctx context.Context, driver neo4j.DriverWithContext) (err error) {
	res, err := neo4j.ExecuteQuery(ctx, driver, `create(a:Person{name:"张三"})-[r:FOLLOWS{since:1997}]->(b:Person{name:"罗翔"}) return a,b,r`, map[string]any{}, neo4j.EagerResultTransformer)
	if err != nil {
		return
	}
	fmt.Println(res)
	return
}

// 修改节点
func updateItem() {

}

// 获取节点
func getItem(ctx context.Context, driver neo4j.DriverWithContext) (*Item, error) {
	res, err := neo4j.ExecuteQuery(ctx, driver, `MATCH (n:GoItem) RETURN n`, nil, neo4j.EagerResultTransformer)
	if err != nil {
		return nil, err
	}
	var item Item
	if len(res.Records) > 0 {
		v, _, err := neo4j.GetRecordValue[neo4j.Node](res.Records[0], "n")
		if err != nil {
			return nil, err
		}
		item.Name, err = neo4j.GetProperty[string](v, "name")
		if err != nil {
			return nil, err
		}
		item.Id, err = neo4j.GetProperty[int64](v, "id")
		if err != nil {
			return nil, err
		}
	}
	return &item, nil
}

// 创建节点
func createItem(ctx context.Context, driver neo4j.DriverWithContext) (*Item, error) {
	result, err := neo4j.ExecuteQuery(ctx, driver,
		"CREATE (n:Person {name: $name }) RETURN n",
		map[string]any{
			"name": "张三",
		}, neo4j.EagerResultTransformer)
	if err != nil {
		return nil, err
	}
	itemNode, _, err := neo4j.GetRecordValue[neo4j.Node](result.Records[0], "n")
	if err != nil {
		return nil, fmt.Errorf("could not find node n")
	}
	name, err := neo4j.GetProperty[string](itemNode, "name")
	if err != nil {
		return nil, err
	}
	return &Item{Name: name}, nil
}

type Item struct {
	Id   int64
	Name string
}

func (i Item) String() string {
	return fmt.Sprintf("Item (id: %d, name: %q)", i.Id, i.Name)
}
